From: Matthieu Gallien Date: Fri, 23 May 2025 17:53:41 +0000 (+0200) Subject: fix(permissions): handle properly CanRead permission from server X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1^2~13^2~1^2~23^2 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/success/%22http:/www.example.com/cgi/success?a=commitdiff_plain;h=34068fb2b18e66c0b56324e89af0ced9f19c4110;p=nextcloud-desktop.git fix(permissions): handle properly CanRead permission from server if Readable permissions is missing, do nto try to download the file if a file was downlaoded but Readable permission is now missing, remove it Signed-off-by: Matthieu Gallien --- diff --git a/src/common/remotepermissions.cpp b/src/common/remotepermissions.cpp index 8e1f088e8..fc75c954d 100644 --- a/src/common/remotepermissions.cpp +++ b/src/common/remotepermissions.cpp @@ -27,7 +27,7 @@ namespace OCC { Q_LOGGING_CATEGORY(lcRemotePermissions, "nextcloud.sync.remotepermissions", QtInfoMsg) -static const char letters[] = " WDNVCKRSMm"; +static const char letters[] = " GWDNVCKRSMm"; template @@ -102,6 +102,7 @@ RemotePermissions RemotePermissions::fromServerString(const QString &value, MountedPermissionAlgorithm algorithm, const QMap &otherProperties) { + qCInfo(lcRemotePermissions()) << "decoding" << value; return internalFromServerString(value, otherProperties, algorithm); } @@ -109,6 +110,7 @@ RemotePermissions RemotePermissions::fromServerString(const QString &value, MountedPermissionAlgorithm algorithm, const QVariantMap &otherProperties) { + qCInfo(lcRemotePermissions()) << "decoding" << value; return internalFromServerString(value, otherProperties, algorithm); } diff --git a/src/common/remotepermissions.h b/src/common/remotepermissions.h index a84c359d3..1bb6e9e74 100644 --- a/src/common/remotepermissions.h +++ b/src/common/remotepermissions.h @@ -41,18 +41,19 @@ private: public: enum Permissions { - CanWrite = 1, // W - CanDelete = 2, // D - CanRename = 3, // N - CanMove = 4, // V - CanAddFile = 5, // C - CanAddSubDirectories = 6, // K - CanReshare = 7, // R + CanRead = 1, // G + CanWrite, // W + CanDelete, // D + CanRename, // N + CanMove, // V + CanAddFile, // C + CanAddSubDirectories, // K + CanReshare, // R // Note: on the server, this means SharedWithMe, but in discoveryphase.cpp we also set // this permission when the server reports the any "share-types" - IsShared = 8, // S - IsMounted = 9, // M - IsMountedSub = 10, // m (internal: set if the parent dir has IsMounted) + IsShared, // S + IsMounted, // M + IsMountedSub, // m (internal: set if the parent dir has IsMounted) // Note: when adding support for more permissions, we need to invalid the cache in the database. // (by setting forceRemoteDiscovery in SyncJournalDb::checkConnect) diff --git a/src/gui/tray/activitydata.cpp b/src/gui/tray/activitydata.cpp index f0fb09b18..df6b25096 100644 --- a/src/gui/tray/activitydata.cpp +++ b/src/gui/tray/activitydata.cpp @@ -130,7 +130,6 @@ OCC::Activity Activity::fromActivityJson(const QJsonObject &json, const AccountP auto word = match.captured(1); word.remove(subjectRichParameterBracesRe); - Q_ASSERT(activity._subjectRichParameters.contains(word)); displayString = displayString.replace(match.captured(1), activity._subjectRichParameters[word].value().name); } diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index a97585a18..5d2ab48e4 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -858,6 +858,9 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it item->_modtime = serverEntry.modtime; item->_size = sizeOnServer; item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + } else if (serverEntry.isValid() && !serverEntry.isDirectory && !serverEntry.remotePerm.isNull() && !serverEntry.remotePerm.hasPermission(RemotePermissions::CanRead)) { + item->_instruction = CSYNC_INSTRUCTION_REMOVE; + item->_direction = SyncFileItem::Down; } else if (dbEntry._remotePerm != serverEntry.remotePerm || dbEntry._fileId != serverEntry.fileId || metaDataSizeNeedsUpdateForE2EeFilePlaceholder) { if (metaDataSizeNeedsUpdateForE2EeFilePlaceholder) { // we are updating placeholder sizes after migrating from older versions with VFS + E2EE implicit hydration not supported @@ -921,6 +924,13 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it return; } + if (serverEntry.isValid() && !serverEntry.isDirectory && !serverEntry.remotePerm.isNull() && !serverEntry.remotePerm.hasPermission(RemotePermissions::CanRead)) { + item->_instruction = CSYNC_INSTRUCTION_IGNORE; + emit _discoveryData->itemDiscovered(item); + + return; + } + // Potential NEW/NEW conflict is handled in AnalyzeLocal if (localEntry.isValid()) { postProcessServerNew(item, path, localEntry, serverEntry, dbEntry); diff --git a/test/sharetestutils.cpp b/test/sharetestutils.cpp index 797c89a8f..1f9f5e2d2 100644 --- a/test/sharetestutils.cpp +++ b/test/sharetestutils.cpp @@ -153,6 +153,7 @@ void ShareTestHelper::setup() const auto fakeFileInfo = fakeFolder.remoteModifier().find(testFileName); QVERIFY(fakeFileInfo); + fakeFileInfo->permissions.setPermission(RemotePermissions::CanRead); fakeFileInfo->permissions.setPermission(RemotePermissions::CanReshare); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); diff --git a/test/syncenginetestutils.cpp b/test/syncenginetestutils.cpp index 58fecc6e8..f05effdb4 100644 --- a/test/syncenginetestutils.cpp +++ b/test/syncenginetestutils.cpp @@ -406,7 +406,7 @@ FakePropfindReply::FakePropfindReply(FileInfo &remoteRootFileInfo, QNetworkAcces xml.writeTextElement(davUri, QStringLiteral("getlastmodified"), stringDate); xml.writeTextElement(davUri, QStringLiteral("getcontentlength"), QString::number(fileInfo.size)); xml.writeTextElement(davUri, QStringLiteral("getetag"), QStringLiteral("\"%1\"").arg(QString::fromLatin1(fileInfo.etag))); - xml.writeTextElement(ocUri, QStringLiteral("permissions"), !fileInfo.permissions.isNull() ? QString(fileInfo.permissions.toString()) : fileInfo.isShared ? QStringLiteral("SRDNVCKW") : QStringLiteral("RDNVCKW")); + xml.writeTextElement(ocUri, QStringLiteral("permissions"), !fileInfo.permissions.isNull() ? QString(fileInfo.permissions.toString()) : fileInfo.isShared ? QStringLiteral("GSRDNVCKW") : QStringLiteral("GRDNVCKW")); xml.writeTextElement(ocUri, QStringLiteral("share-permissions"), QString::number(static_cast(OCC::SharePermissions(OCC::SharePermissionRead | OCC::SharePermissionUpdate | OCC::SharePermissionCreate | diff --git a/test/testfolderman.cpp b/test/testfolderman.cpp index fa01cb51a..bec0a7e65 100644 --- a/test/testfolderman.cpp +++ b/test/testfolderman.cpp @@ -178,6 +178,7 @@ private slots: fakeFolder.remoteModifier().insert(firstSharePath, 100); const auto firstShare = fakeFolder.remoteModifier().find(firstSharePath); QVERIFY(firstShare); + firstShare->permissions.setPermission(OCC::RemotePermissions::CanRead); firstShare->permissions.setPermission(OCC::RemotePermissions::IsShared); fakeFolder.remoteModifier().mkdir("A/B"); @@ -185,6 +186,7 @@ private slots: fakeFolder.remoteModifier().insert(secondSharePath, 100); const auto secondShare = fakeFolder.remoteModifier().find(secondSharePath); QVERIFY(secondShare); + secondShare->permissions.setPermission(OCC::RemotePermissions::CanRead); secondShare->permissions.setPermission(OCC::RemotePermissions::IsShared); FolderMan *folderman = FolderMan::instance(); diff --git a/test/testpermissions.cpp b/test/testpermissions.cpp index 5de4c4dd6..fb16bb1e4 100644 --- a/test/testpermissions.cpp +++ b/test/testpermissions.cpp @@ -125,11 +125,11 @@ private slots: //create some files auto insertIn = [&](const QString &dir) { - fakeFolder.remoteModifier().insert(dir + "normalFile_PERM_WVND_.data", 100 ); - fakeFolder.remoteModifier().insert(dir + "cannotBeRemoved_PERM_WVN_.data", 101 ); - fakeFolder.remoteModifier().insert(dir + "canBeRemoved_PERM_D_.data", 102 ); - fakeFolder.remoteModifier().insert(dir + "cannotBeModified_PERM_DVN_.data", cannotBeModifiedSize , 'A'); - fakeFolder.remoteModifier().insert(dir + "canBeModified_PERM_W_.data", canBeModifiedSize ); + fakeFolder.remoteModifier().insert(dir + "normalFile_PERM_GWVND_.data", 100 ); + fakeFolder.remoteModifier().insert(dir + "cannotBeRemoved_PERM_GWVN_.data", 101 ); + fakeFolder.remoteModifier().insert(dir + "canBeRemoved_PERM_GD_.data", 102 ); + fakeFolder.remoteModifier().insert(dir + "cannotBeModified_PERM_GDVN_.data", cannotBeModifiedSize , 'A'); + fakeFolder.remoteModifier().insert(dir + "canBeModified_PERM_GW_.data", canBeModifiedSize ); }; //put them in some directories @@ -139,7 +139,7 @@ private slots: insertIn("readonlyDirectory_PERM_M_/" ); fakeFolder.remoteModifier().mkdir("readonlyDirectory_PERM_M_/subdir_PERM_CK_"); fakeFolder.remoteModifier().mkdir("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_"); - fakeFolder.remoteModifier().insert("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data", 100); + fakeFolder.remoteModifier().insert("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_GWVND_.data", 100); applyPermissionsFromName(fakeFolder.remoteModifier()); QVERIFY(fakeFolder.syncOnce()); @@ -210,13 +210,13 @@ private slots: //1. remove the file than cannot be removed // (they should be recovered) - fakeFolder.localModifier().remove("normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_WVN_.data"); - removeReadOnly("readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data"); + fakeFolder.localModifier().remove("normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_GWVN_.data"); + removeReadOnly("readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_GWVN_.data"); //2. remove the file that can be removed // (they should properly be gone) - removeReadOnly("normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data"); - removeReadOnly("readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data"); + removeReadOnly("normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_GD_.data"); + removeReadOnly("readonlyDirectory_PERM_M_/canBeRemoved_PERM_GD_.data"); //3. Edit the files that cannot be modified // (they should be recovered, and a conflict shall be created) @@ -225,19 +225,19 @@ private slots: QFile(fakeFolder.localPath() + file).setPermissions(QFile::WriteOwner | QFile::ReadOwner); fakeFolder.localModifier().appendByte(file); }; - editReadOnly("normalDirectory_PERM_CKDNV_/cannotBeModified_PERM_DVN_.data"); + editReadOnly("normalDirectory_PERM_CKDNV_/cannotBeModified_PERM_GDVN_.data"); #if !defined Q_OS_WINDOWS - editReadOnly("readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data"); + editReadOnly("readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data"); #endif //4. Edit other files // (they should be uploaded) - fakeFolder.localModifier().appendByte("normalDirectory_PERM_CKDNV_/canBeModified_PERM_W_.data"); - fakeFolder.localModifier().appendByte("readonlyDirectory_PERM_M_/canBeModified_PERM_W_.data"); + fakeFolder.localModifier().appendByte("normalDirectory_PERM_CKDNV_/canBeModified_PERM_GW_.data"); + fakeFolder.localModifier().appendByte("readonlyDirectory_PERM_M_/canBeModified_PERM_GW_.data"); //5. Create a new file in a read write folder // (should be uploaded) - fakeFolder.localModifier().insert("normalDirectory_PERM_CKDNV_/newFile_PERM_WDNV_.data", 106 ); + fakeFolder.localModifier().insert("normalDirectory_PERM_CKDNV_/newFile_PERM_GWDNV_.data", 106 ); applyPermissionsFromName(fakeFolder.remoteModifier()); //do the sync @@ -247,26 +247,26 @@ private slots: //1. // File should be recovered - QVERIFY(currentLocalState.find("normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_WVN_.data")); + QVERIFY(currentLocalState.find("normalDirectory_PERM_CKDNV_/cannotBeRemoved_PERM_GWVN_.data")); #if !defined Q_OS_WINDOWS - QCOMPARE(currentLocalState.find("readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data")->size, cannotBeModifiedSize); + QCOMPARE(currentLocalState.find("readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data")->size, cannotBeModifiedSize); #endif - QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data")); + QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_GWVN_.data")); //2. // File should be deleted - QVERIFY(!currentLocalState.find("normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_D_.data")); - QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/canBeRemoved_PERM_D_.data")); + QVERIFY(!currentLocalState.find("normalDirectory_PERM_CKDNV_/canBeRemoved_PERM_GD_.data")); + QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/canBeRemoved_PERM_GD_.data")); //3. // File should be recovered - QCOMPARE(currentLocalState.find("normalDirectory_PERM_CKDNV_/cannotBeModified_PERM_DVN_.data")->size, cannotBeModifiedSize); + QCOMPARE(currentLocalState.find("normalDirectory_PERM_CKDNV_/cannotBeModified_PERM_GDVN_.data")->size, cannotBeModifiedSize); // and conflict created - auto c1 = findConflict(currentLocalState, "normalDirectory_PERM_CKDNV_/cannotBeModified_PERM_DVN_.data"); + auto c1 = findConflict(currentLocalState, "normalDirectory_PERM_CKDNV_/cannotBeModified_PERM_GDVN_.data"); QVERIFY(c1); QCOMPARE(c1->size, cannotBeModifiedSize + 1); #if !defined Q_OS_WINDOWS - auto c2 = findConflict(currentLocalState, "readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data"); + auto c2 = findConflict(currentLocalState, "readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data"); QVERIFY(c2); QCOMPARE(c2->size, cannotBeModifiedSize + 1); #endif @@ -277,12 +277,12 @@ private slots: #endif //4. File should be updated, that's tested by assertLocalAndRemoteDir - QCOMPARE(currentLocalState.find("normalDirectory_PERM_CKDNV_/canBeModified_PERM_W_.data")->size, canBeModifiedSize + 1); - QCOMPARE(currentLocalState.find("readonlyDirectory_PERM_M_/canBeModified_PERM_W_.data")->size, canBeModifiedSize + 1); + QCOMPARE(currentLocalState.find("normalDirectory_PERM_CKDNV_/canBeModified_PERM_GW_.data")->size, canBeModifiedSize + 1); + QCOMPARE(currentLocalState.find("readonlyDirectory_PERM_M_/canBeModified_PERM_GW_.data")->size, canBeModifiedSize + 1); //5. // the file should be in the server and local - QVERIFY(currentLocalState.find("normalDirectory_PERM_CKDNV_/newFile_PERM_WDNV_.data")); + QVERIFY(currentLocalState.find("normalDirectory_PERM_CKDNV_/newFile_PERM_GWDNV_.data")); // Both side should still be the same QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -291,7 +291,7 @@ private slots: //6. Create a new file in a read only folder // (they should not be uploaded) - insertReadOnly("readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data", 105 ); + insertReadOnly("readonlyDirectory_PERM_M_/newFile_PERM_GWDNV_.data", 105 ); applyPermissionsFromName(fakeFolder.remoteModifier()); // error: can't upload to readonly @@ -302,8 +302,8 @@ private slots: //6. // The file should not exist on the remote, and not be there - QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data")); - QVERIFY(!fakeFolder.currentRemoteState().find("readonlyDirectory_PERM_M_/newFile_PERM_WDNV_.data")); + QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/newFile_PERM_GWDNV_.data")); + QVERIFY(!fakeFolder.currentRemoteState().find("readonlyDirectory_PERM_M_/newFile_PERM_GWDNV_.data")); // Both side should still be the same QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -316,7 +316,7 @@ private slots: QVERIFY(fakeFolder.syncOnce()); assertCsyncJournalOk(fakeFolder.syncJournal()); currentLocalState = fakeFolder.currentLocalState(); - QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_WVN_.data")); + QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/cannotBeRemoved_PERM_GWVN_.data")); QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_")); // the subdirectory had delete permissions, but, it was within the recovered directory, so must also get recovered QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_")); @@ -341,16 +341,16 @@ private slots: QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_")); // contents moved (had move permissions) QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_")); - QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data")); + QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_GWVND_.data")); // new still exist (and is uploaded) - QVERIFY(currentLocalState.find("normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data")); + QVERIFY(currentLocalState.find("normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_/subsubdir_PERM_CKDNV_/normalFile_PERM_GWVND_.data")); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); // restore for further tests fakeFolder.remoteModifier().mkdir("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_"); - fakeFolder.remoteModifier().insert("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data"); + fakeFolder.remoteModifier().insert("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_GWVND_.data"); applyPermissionsFromName(fakeFolder.remoteModifier()); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -364,7 +364,7 @@ private slots: QVERIFY(fakeFolder.syncOnce()); assertCsyncJournalOk(fakeFolder.syncJournal()); - QVERIFY(fakeFolder.currentLocalState().find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data" )); + QVERIFY(fakeFolder.currentLocalState().find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_GWVND_.data" )); //1. rename a directory in a read only folder //Missing directory should be restored @@ -382,9 +382,9 @@ private slots: // old name restored QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_" )); // including contents - QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data" )); + QVERIFY(currentLocalState.find("readonlyDirectory_PERM_M_/subdir_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_GWVND_.data" )); // new no longer exists - QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/newname_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data" )); + QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/newname_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_GWVND_.data" )); // but is not on server: should have been locally removed QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/newname_PERM_CK_")); @@ -394,7 +394,7 @@ private slots: // but still on the server: the rename causing an error meant the deletes didn't execute QVERIFY(fakeFolder.currentRemoteState().find("normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_")); // new no longer exists - QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/moved_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_WVND_.data" )); + QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/moved_PERM_CK_/subsubdir_PERM_CKDNV_/normalFile_PERM_GWVND_.data" )); // should have been cleaned up as invalid item inside read-only folder QVERIFY(!currentLocalState.find("readonlyDirectory_PERM_M_/moved_PERM_CK_")); fakeFolder.remoteModifier().remove("normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_"); @@ -405,20 +405,20 @@ private slots: //###################################################################### qInfo( "multiple restores of a file create different conflict files" ); - fakeFolder.remoteModifier().insert("readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data"); + fakeFolder.remoteModifier().insert("readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data"); applyPermissionsFromName(fakeFolder.remoteModifier()); QVERIFY(fakeFolder.syncOnce()); - editReadOnly("readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data"); - fakeFolder.localModifier().setContents("readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data", 's'); + editReadOnly("readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data"); + fakeFolder.localModifier().setContents("readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data", 's'); //do the sync applyPermissionsFromName(fakeFolder.remoteModifier()); QVERIFY(fakeFolder.syncOnce()); assertCsyncJournalOk(fakeFolder.syncJournal()); QThread::sleep(1); // make sure changes have different mtime - editReadOnly("readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data"); - fakeFolder.localModifier().setContents("readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data", 'd'); + editReadOnly("readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data"); + fakeFolder.localModifier().setContents("readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data", 'd'); //do the sync applyPermissionsFromName(fakeFolder.remoteModifier()); @@ -428,7 +428,7 @@ private slots: // there should be two conflict files currentLocalState = fakeFolder.currentLocalState(); int count = 0; - while (auto i = findConflict(currentLocalState, "readonlyDirectory_PERM_M_/cannotBeModified_PERM_DVN_.data")) { + while (auto i = findConflict(currentLocalState, "readonlyDirectory_PERM_M_/cannotBeModified_PERM_GDVN_.data")) { QVERIFY((i->contentChar == 's') || (i->contentChar == 'd')); removeReadOnly(i->path()); currentLocalState = fakeFolder.currentLocalState(); @@ -487,10 +487,10 @@ private slots: rm.insert("zallowed/sub/file"); rm.insert("zallowed/sub2/file"); - setAllPerm(rm.find("norename"), RemotePermissions::fromServerString("WDVCK")); - setAllPerm(rm.find("nomove"), RemotePermissions::fromServerString("WDNCK")); - setAllPerm(rm.find("nocreatefile"), RemotePermissions::fromServerString("WDNVK")); - setAllPerm(rm.find("nocreatedir"), RemotePermissions::fromServerString("WDNVC")); + setAllPerm(rm.find("norename"), RemotePermissions::fromServerString("GWDVCK")); + setAllPerm(rm.find("nomove"), RemotePermissions::fromServerString("GWDNCK")); + setAllPerm(rm.find("nocreatefile"), RemotePermissions::fromServerString("GWDNVK")); + setAllPerm(rm.find("nocreatedir"), RemotePermissions::fromServerString("GWDNVC")); QVERIFY(fakeFolder.syncOnce()); @@ -715,7 +715,7 @@ private slots: remote.mkdir("testFolder/newSubFolder"); remote.create("testFolder/testFile", 12, '9'); remote.create("testFolder/testReadOnlyFile", 13, '8'); - remote.find("testFolder/testReadOnlyFile")->permissions = RemotePermissions::fromServerString("m"); + remote.find("testFolder/testReadOnlyFile")->permissions = RemotePermissions::fromServerString("mG"); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -746,7 +746,7 @@ private slots: remote.find("readOnlyFolder")->permissions = RemotePermissions::fromServerString("M"); remote.find("readOnlyFolder/test")->permissions = RemotePermissions::fromServerString("m"); - remote.find("readOnlyFolder/readOnlyFile.txt")->permissions = RemotePermissions::fromServerString("m"); + remote.find("readOnlyFolder/readOnlyFile.txt")->permissions = RemotePermissions::fromServerString("mG"); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -776,7 +776,7 @@ private slots: remote.find("readOnlyFolder")->permissions = RemotePermissions::fromServerString("M"); remote.find("readOnlyFolder/test")->permissions = RemotePermissions::fromServerString("m"); - remote.find("readOnlyFolder/readOnlyFile.txt")->permissions = RemotePermissions::fromServerString("m"); + remote.find("readOnlyFolder/readOnlyFile.txt")->permissions = RemotePermissions::fromServerString("mG"); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -810,7 +810,7 @@ private slots: remote.find("readOnlyFolder")->permissions = RemotePermissions::fromServerString("M"); remote.find("readOnlyFolder/child")->permissions = RemotePermissions::fromServerString("m"); remote.find("readOnlyFolder/test")->permissions = RemotePermissions::fromServerString("m"); - remote.find("readOnlyFolder/readOnlyFile.txt")->permissions = RemotePermissions::fromServerString("m"); + remote.find("readOnlyFolder/readOnlyFile.txt")->permissions = RemotePermissions::fromServerString("mG"); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); @@ -843,13 +843,13 @@ private slots: remote.find("readOnlyFolder")->permissions = RemotePermissions::fromServerString("M"); remote.find("readOnlyFolder/test")->permissions = RemotePermissions::fromServerString("m"); - remote.find("readOnlyFolder/readOnlyFile.txt")->permissions = RemotePermissions::fromServerString("m"); + remote.find("readOnlyFolder/readOnlyFile.txt")->permissions = RemotePermissions::fromServerString("mG"); QVERIFY(fakeFolder.syncOnce()); QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); remote.insert("readOnlyFolder/test/newFile.txt"); - remote.find("readOnlyFolder/test/newFile.txt")->permissions = RemotePermissions::fromServerString("m"); + remote.find("readOnlyFolder/test/newFile.txt")->permissions = RemotePermissions::fromServerString("mG"); remote.mkdir("readOnlyFolder/test/newFolder"); remote.find("readOnlyFolder/test/newFolder")->permissions = RemotePermissions::fromServerString("m"); remote.appendByte("readOnlyFolder/readOnlyFile.txt"); @@ -867,6 +867,69 @@ private slots: QVERIFY(ensureReadOnlyItem("/readOnlyFolder/test/newFile.txt")); QVERIFY(ensureReadOnlyItem("/readOnlyFolder/newFolder")); } + + void testForbiddenDownload() + { + FakeFolder fakeFolder{FileInfo{}}; + QObject parent; + + fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) -> QNetworkReply * { + Q_UNUSED(outgoingData) + + if (op == QNetworkAccessManager::GetOperation) { + return new FakeErrorReply(op, request, &parent, 403, "Access to this shared resource has been denied because its download permission is disabled."); + } + + return nullptr; + }); + + fakeFolder.remoteModifier().insert("file"); + + setAllPerm(fakeFolder.remoteModifier().find("file"), RemotePermissions::fromServerString("DNVRS")); + + // also hook into discovery!! + SyncFileItemVector discovery; + connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToPropagate, this, [&discovery](auto v) { discovery = v; }); + ItemCompletedSpy completeSpy(fakeFolder); + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(itemInstruction(completeSpy, "file", CSYNC_INSTRUCTION_IGNORE)); + QVERIFY(discoveryInstruction(discovery, "file", CSYNC_INSTRUCTION_IGNORE)); + } + + void testExistingFileBecomeForbiddenDownload() + { + FakeFolder fakeFolder{FileInfo{}}; + QObject parent; + + fakeFolder.remoteModifier().insert("file"); + auto fileInfo = fakeFolder.remoteModifier().find("file"); + Q_ASSERT(fileInfo); + fileInfo->isShared = true; + + QVERIFY(fakeFolder.syncOnce()); + + fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) -> QNetworkReply * { + Q_UNUSED(outgoingData) + + if (op == QNetworkAccessManager::GetOperation) { + return new FakeErrorReply(op, request, &parent, 403, "Access to this shared resource has been denied because its download permission is disabled."); + } + + return nullptr; + }); + + setAllPerm(fileInfo, RemotePermissions::fromServerString("DNVRS")); + + // also hook into discovery!! + SyncFileItemVector discovery; + connect(&fakeFolder.syncEngine(), &SyncEngine::aboutToPropagate, this, [&discovery](auto v) { discovery = v; }); + ItemCompletedSpy completeSpy(fakeFolder); + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(itemInstruction(completeSpy, "file", CSYNC_INSTRUCTION_REMOVE)); + QVERIFY(discoveryInstruction(discovery, "file", CSYNC_INSTRUCTION_REMOVE)); + } }; QTEST_GUILESS_MAIN(TestPermissions) diff --git a/test/testremotediscovery.cpp b/test/testremotediscovery.cpp index a688b8d92..5eef1e7b9 100644 --- a/test/testremotediscovery.cpp +++ b/test/testremotediscovery.cpp @@ -27,7 +27,7 @@ struct MissingPermissionsPropfindReply : FakePropfindReply { const QNetworkRequest &request, QObject *parent) : FakePropfindReply(remoteRootFileInfo, op, request, parent) { // If the propfind contains a single file without permissions, this is a server error - const char toRemove[] = "RDNVCKW"; + const char toRemove[] = "GRDNVCKW"; auto pos = payload.indexOf(toRemove, payload.size()/2); QVERIFY(pos > 0); payload.remove(pos, sizeof(toRemove) - 1); diff --git a/test/testsyncengine.cpp b/test/testsyncengine.cpp index cd10e51bb..5a53904a5 100644 --- a/test/testsyncengine.cpp +++ b/test/testsyncengine.cpp @@ -2255,9 +2255,9 @@ private slots: fakeFolder.remoteModifier().insert("file3"); fakeFolder.remoteModifier().find("folder")->permissions = RemotePermissions::fromServerString("DNVS"); - fakeFolder.remoteModifier().find("folder/file1.lnk")->permissions = RemotePermissions::fromServerString("S"); - fakeFolder.remoteModifier().find("folder/file2.lnk")->permissions = RemotePermissions::fromServerString("S"); - fakeFolder.remoteModifier().find("folder/file3.lnk")->permissions = RemotePermissions::fromServerString("S"); + fakeFolder.remoteModifier().find("folder/file1.lnk")->permissions = RemotePermissions::fromServerString("SG"); + fakeFolder.remoteModifier().find("folder/file2.lnk")->permissions = RemotePermissions::fromServerString("SG"); + fakeFolder.remoteModifier().find("folder/file3.lnk")->permissions = RemotePermissions::fromServerString("SG"); fakeFolder.remoteModifier().find("abcdefabcdefabcdefabcdefabcdefabcd")->permissions = RemotePermissions::fromServerString("DNVS"); fakeFolder.remoteModifier().find("abcdefabcdefabcdefabcdefabcdefabcd/abcdef abcdef abcdef a")->permissions = RemotePermissions::fromServerString("DNVS"); @@ -2267,7 +2267,7 @@ private slots: fakeFolder.remoteModifier().find("abcdefabcdefabcdefabcdefabcdefabcd/abcdef abcdef abcdef a/abcdef abcdef/abcdef acbdef abcd/123abcdefabcdef1/123123abcdef123 abcdef1")->permissions = RemotePermissions::fromServerString("DNVS"); fakeFolder.remoteModifier().find("abcdefabcdefabcdefabcdefabcdefabcd/abcdef abcdef abcdef a/abcdef abcdef/abcdef acbdef abcd/123abcdefabcdef1/123123abcdef123 abcdef1/12abcabc")->permissions = RemotePermissions::fromServerString("DNVS"); fakeFolder.remoteModifier().find("abcdefabcdefabcdefabcdefabcdefabcd/abcdef abcdef abcdef a/abcdef abcdef/abcdef acbdef abcd/123abcdefabcdef1/123123abcdef123 abcdef1/12abcabc/12abcabd")->permissions = RemotePermissions::fromServerString("DNVS"); - fakeFolder.remoteModifier().find("abcdefabcdefabcdefabcdefabcdefabcd/abcdef abcdef abcdef a/abcdef abcdef/abcdef acbdef abcd/123abcdefabcdef1/123123abcdef123 abcdef1/12abcabc/12abcabd/this is a long long long long long long long long long long long long long long long long l.docx - Sh.lnk")->permissions = RemotePermissions::fromServerString("S"); + fakeFolder.remoteModifier().find("abcdefabcdefabcdefabcdefabcdefabcd/abcdef abcdef abcdef a/abcdef abcdef/abcdef acbdef abcd/123abcdefabcdef1/123123abcdef123 abcdef1/12abcabc/12abcabd/this is a long long long long long long long long long long long long long long long long l.docx - Sh.lnk")->permissions = RemotePermissions::fromServerString("SG"); QVERIFY(fakeFolder.syncOnce()); } diff --git a/test/testsyncmove.cpp b/test/testsyncmove.cpp index 52d0051b6..04d9456e0 100644 --- a/test/testsyncmove.cpp +++ b/test/testsyncmove.cpp @@ -326,7 +326,7 @@ private slots: fakeFolder.remoteModifier().mkdir("external-storage"); auto externalStorage = fakeFolder.remoteModifier().find("external-storage"); externalStorage->extraDavProperties = "true"; - setAllPerm(externalStorage, RemotePermissions::fromServerString("WDNVCKRM")); + setAllPerm(externalStorage, RemotePermissions::fromServerString("WDNVCKRMG")); QVERIFY(fakeFolder.syncOnce()); OperationCounter operationCounter; @@ -1159,7 +1159,7 @@ private slots: fakeFolder.remoteModifier().mkdir("FolA"); auto groupFolderRoot = fakeFolder.remoteModifier().find("FolA"); groupFolderRoot->extraDavProperties = "true"; - setAllPerm(groupFolderRoot, RemotePermissions::fromServerString("WDNVCKRM")); + setAllPerm(groupFolderRoot, RemotePermissions::fromServerString("WDNVCKRMG")); fakeFolder.remoteModifier().mkdir("FolA/FolB"); fakeFolder.remoteModifier().mkdir("FolA/FolB/FolC"); fakeFolder.remoteModifier().mkdir("FolA/FolB/FolC/FolD"); @@ -1196,7 +1196,7 @@ private slots: fakeFolder.remoteModifier().mkdir("FolA"); auto groupFolderRoot = fakeFolder.remoteModifier().find("FolA"); groupFolderRoot->extraDavProperties = "true"; - setAllPerm(groupFolderRoot, RemotePermissions::fromServerString("WDNVCKRM")); + setAllPerm(groupFolderRoot, RemotePermissions::fromServerString("WDNVCKRMG")); fakeFolder.remoteModifier().mkdir("FolA/FolB"); fakeFolder.remoteModifier().mkdir("FolA/FolB/FolC"); fakeFolder.remoteModifier().mkdir("FolA/FolB/FolC/FolD");